package com.example.drcbackend.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.drcbackend.Mapper.DbMapper;
import com.example.drcbackend.entity.functionaldependencies;
import com.example.drcbackend.Mapper.functionaldependenciesMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(isolation = Isolation.SERIALIZABLE)
// 连接池优先级，不加会导致表结构改变，原因未知
/* 事务隔离级别问题
        问题分析：事务隔离级别可能影响了查询操作。如果隔离级别设置为 READ_COMMITTED 或更低，查询操作可能会读取到未提交的表结构变化。
        场景示例：
        在事务 A 中，表被删除并重建（未提交）。
        在事务 B 中，执行查询操作时读取到了事务 A 中的表结构变化，导致错误。 */
public class RepairCheckingService {

    private static final Logger logger = LoggerFactory.getLogger(RepairCheckingService.class);

    @Autowired
    private ConsistencyService consistencyService;
    @Autowired
    private Constant_cService cs;
    @Autowired
    private functionaldependenciesMapper fm;
    public RepairCheckResult RepairChecking(int DBid, int setdbid) {
        try {
            // 读取两个SQL文件的内容
            String dbFilePath = "E:/SQL_test/" + DBid + ".sql";
            List<String> dbLines = Files.readAllLines(Paths.get(dbFilePath), StandardCharsets.UTF_8);
            String subFilePath = "E:/SQL_test/" + setdbid + ".sql";
            List<String> subLines = Files.readAllLines(Paths.get(subFilePath), StandardCharsets.UTF_8);

            // 分离DDL和DML语句
            List<String> dbDDL = new ArrayList<>();
            List<String> dbInserts = new ArrayList<>();
            separateDDLAndDML(dbLines, dbDDL, dbInserts);

            List<String> subDDL = new ArrayList<>();
            List<String> subInserts = new ArrayList<>();
            separateDDLAndDML(subLines, subDDL, subInserts);

            // 计算差集（r的插入语句 - r'的插入语句）
            Set<String> difference = new HashSet<>(dbInserts);
            difference.removeAll(new HashSet<>(subInserts));

            // 获取常数c
            int c = cs.Constant_c(DBid); // 常数c，完全依赖于F这里是按照BCNF来求的

            // 如果差集为空，直接返回false（无法找到非空A*）
            if (difference.isEmpty()) {
                return new RepairCheckResult(false, null, c);
            }

            int maxSubsetSize = Math.min(c, difference.size());

            // 遍历所有非空子集（大小1到maxSubsetSize）
            for (int i = 1; i <= maxSubsetSize; i++) {
                for (Set<String> subset : combinations(difference, i)) {
                    // 合并SQL内容：sub的DDL + sub的插入 + A*的插入
                    List<String> mergedSql = new ArrayList<>(subDDL);
                    mergedSql.addAll(subInserts);
                    mergedSql.addAll(subset);

                    // 检查合并后的实例是否满足Σ（使用原DBid的函数依赖集）
                    if (consistencyService.checkSqlConsistency(mergedSql, DBid, new ArrayList<>())) {
                        return new RepairCheckResult(false, subset, c);// 找到即为修复检查未通过
                    }
                }
            }

            return new RepairCheckResult(true, null, c);// 未找到则通过
        } catch (Exception e) {
            logger.info("修复检查成功 DBid={}, setdbid={}", DBid, setdbid, e);
            return new RepairCheckResult(false, null, 0);
        }
    }

    // 分离DDL和DML（INSERT）语句
    private void separateDDLAndDML(List<String> lines, List<String> ddl, List<String> inserts) {
        for (String line : lines) {
            String trimmed = line.trim();
            if (!trimmed.isEmpty()) {
                if (trimmed.toUpperCase().startsWith("INSERT")) {
                    inserts.add(line);
                } else {
                    ddl.add(line);
                }
            }
        }
    }
    // 在事务开始之前查询函数依赖集
    public List<functionaldependencies> getFunctionalDependencies(int DBid) {
        LambdaQueryWrapper<functionaldependencies> lqwst = new LambdaQueryWrapper<>();
        lqwst.eq(functionaldependencies::getDbid, DBid);
        return fm.selectList(lqwst);
    }
    // 生成所有k元素的组合（非递归优化版）
    private List<Set<String>> combinations(Set<String> elements, int k) {
        List<Set<String>> result = new ArrayList<>();
        if (k <= 0 || k > elements.size()) return result;

        List<String> elementList = new ArrayList<>(elements);
        int n = elementList.size();
        int[] indices = new int[k];

        // 初始化第一个组合
        for (int i = 0; i < k; i++) {
            indices[i] = i;
        }

        while (true) {
            // 添加当前组合
            Set<String> combination = new HashSet<>();
            for (int index : indices) {
                combination.add(elementList.get(index));
            }
            result.add(combination);

            // 查找下一个组合
            int pos = k - 1;
            while (pos >= 0 && indices[pos] == n - k + pos) {
                pos--;
            }

            if (pos < 0) break;

            indices[pos]++;
            for (int i = pos + 1; i < k; i++) {
                indices[i] = indices[i - 1] + 1;
            }
        }

        return result;
    }
}
